#include <QCoreApplication>
#include "main.h"
#include "utils/logger.h"
#include <QThread>
#include "handlers/sessionhandler.h"
//#include "server/coreserver.h"
#include "server/logonserver.h"

#include "server/udpsever.h"
#include "utils/Config.h"
#include <QFile>
#include <QTextStream>
#include "units/gamemanager.h"
#include "version.h"
#include "network/nettools.h"
Logg::Logger* _log;
QMap<int,QString> TL2CMD_NAMES;
QMap<int, Player*> LPlayers;
QMap<quint64, Game*> LGames;
DataServer* database;

//CoreServer* LoginServer;

LogonServer* LoginServer;
UDPSever* udpServer;
QMap<QTcpSocket* ,Handlers::SessionHandler*> Clients;
Config* CfgFile;
QString wanIP;
quint32 wanIPint;

QString lanIP;
quint32 lanIPint;

unsigned int TCP_PORT;
unsigned int UDP_PORT;
unsigned int UDP_CLIENT;
bool DEBUG_TCP_SEND;
bool DEBUG_TCP_RECV;
bool DEBUG_UDP_SEND;
bool DEBUG_UDP_RECV;
unsigned short* DEBUG_TCP_FILTER;
unsigned int DEBUG_TCP_FILTER_COUNT;
unsigned short* DEBUG_UDP_FILTER;
unsigned int DEBUG_UDP_FILTER_COUNT;
QString WAN_METOD;

int filtered=0;

quint32  GameManager::_PlayersInGame=0;
NetTools* net;
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    #if defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 )
    QString cmd("TITLE TL2Server %1");
        system(cmd.arg(APP_VER).toAscii().data());
    #endif
    _log = new Logg::Logger();
    _log->start();
    _log->LogIt(QString("TL2Server %1").arg(APP_VER));

    init();
    ReadConfig();

    database = new DataServer();
    _log->LogIt("DataBase initialized.");
    LoginServer = new LogonServer();
    LoginServer ->start();
    udpServer = new UDPSever(UDP_PORT);
    udpServer->start();
    return a.exec();
}

void init()
{


    TL2CMD_NAMES[Handlers::Client_Login]="Client_Login";
     // Server_Login        = 0x01,
    TL2CMD_NAMES[Handlers::Client_Discon]="Client_Discon";
      //Server_Discon       = 0x03,
    TL2CMD_NAMES[Handlers::Client_UserData]="Client_UserData";
      //Server_UserData     = 0x09,
    TL2CMD_NAMES[Handlers::Client_ServerInfo]="Client_ServerInfo";
      //Server_ServerInfo   = 0x0B,
    TL2CMD_NAMES[Handlers::Client_GameList]="Client_GameList";
    TL2CMD_NAMES[Handlers::Client_GameInfo]="Client_GameInfo";
      //Server_GameList     = 0x0D,
    TL2CMD_NAMES[Handlers::Client_CreateGame]="Client_CreateGame";
      //Server_CreateGame   = 0x10,
    TL2CMD_NAMES[Handlers::Client_ChangeChar]="Client_ChangeChar";
    TL2CMD_NAMES[Handlers::Client_GameState]="Client_GameState";
    TL2CMD_NAMES[Handlers::Client_JoinGame]="Client_JoinGame";
    TL2CMD_NAMES[Handlers::Client_ConnectPeer]="Client_ConnectPeer";
    TL2CMD_NAMES[Handlers::Client_Validatekey]="Client_Validatekey";
    TL2CMD_NAMES[Handlers::Client_LeaveGame]="Client_LeaveGame";
    TL2CMD_NAMES[Handlers::Client_CloseGame]="Client_CloseGame";

    TL2CMD_NAMES[Handlers::Both_unhandled]="Unknown_packet";

    TL2CMD_NAMES[Handlers::Both_ping]="Both_ping";
}

void ReadConfig()
{
    _log->LogIt("Loading config...");
    CfgFile = new Config("TL2Server.conf");
    TCP_PORT = CfgFile->pInt("PORT.TCP");
    UDP_PORT = CfgFile->pInt("PORT.UDP");
    UDP_CLIENT = CfgFile->pInt("PORT.CLIENT");

    DEBUG_TCP_SEND  = CfgFile->pBool("DEBUG.TCP.SEND");
    DEBUG_TCP_RECV  = CfgFile->pBool("DEBUG.TCP.RECV");
    DEBUG_UDP_SEND  = CfgFile->pBool("DEBUG.UDP.SEND");
    DEBUG_UDP_RECV  = CfgFile->pBool("DEBUG.UDP.RECV");

    QString spliter(CfgFile->pString("DEBUG.TCP.FILTER").c_str());
    QStringList filter=spliter.split(',');
    DEBUG_TCP_FILTER = new unsigned short[sizeof(unsigned short*) * filter.count()];
    DEBUG_TCP_FILTER_COUNT=filter.count();

    QListIterator<QString> itr (filter);
    int i = 0;
    while (itr.hasNext()) {
        QString current = itr.next();
        bool ok;
        DEBUG_TCP_FILTER[i] = current.toUShort(&ok,16);
        i++;
    }

    spliter=CfgFile->pString("DEBUG.UDP.FILTER").c_str();
    filter=spliter.split(',');
    DEBUG_UDP_FILTER = new unsigned short[sizeof(unsigned short*) * filter.count()];
    DEBUG_UDP_FILTER_COUNT=filter.count();

    itr=filter;
     i = 0;
    while (itr.hasNext()) {
        QString current = itr.next();
        bool ok;
        DEBUG_UDP_FILTER[i] = current.toUShort(&ok,16);
        i++;
    }

    WAN_METOD=QString(CfgFile->pString("WAN_METOD").c_str()).toLower();
    lanIP=QString(CfgFile->pString("LAN_BIND").c_str());
    setup_network();
    _log->LogIt(QString("Server status"));
    _log->LogIt(QString("TCP    Port: %1").arg(TCP_PORT));
    _log->LogIt(QString("UDP    Port: %1").arg(UDP_PORT));
    _log->LogIt(QString("Client Port: %1").arg(UDP_CLIENT));
    _log->LogIt(QString("Network Setting"));
    _log->LogIt(QString("Wan IP metod detect: %1").arg(WAN_METOD));
    _log->LogIt(QString("Wan IP: %1").arg(wanIP));
    _log->LogIt(QString("Lan IP: %1").arg(lanIP));
    _log->LogIt(QString("Debug config"));
    _log->LogIt(QString("TCP RECV: %1").arg(DEBUG_TCP_RECV));
    _log->LogIt(QString("TCP SEND: %1").arg(DEBUG_TCP_SEND));
    _log->LogIt(QString("UDP RECV: %1").arg(DEBUG_UDP_RECV));
    _log->LogIt(QString("UDP SEND: %1").arg(DEBUG_UDP_SEND));
    _log->LogIt(QString("Filters : %1").arg(DEBUG_TCP_FILTER_COUNT+DEBUG_UDP_FILTER_COUNT));

}
QString getTestPacket()
{
    QString filename;
    filename =QDir::currentPath();
    filename +="/testPkt.txt";
    QFile file(filename);
    if (!file.open (QIODevice::ReadOnly))
         return QString::null;
    QTextStream stream ( &file );
    QString line;
    QString pool;
    while( !stream.atEnd() ) {
         line = stream.readLine();
         line = line.split('#')[0];
         pool+=line.trimmed().remove('\n').remove('\r').remove('\t').remove(' ');
         //pool+=line.remove(' ');
    }
    file.close();
    return pool;
}
bool FILTER_TCP(quint16 cmd){
    for(int i=0;i<DEBUG_TCP_FILTER_COUNT;i++)
        if(DEBUG_TCP_FILTER[i]==cmd)
        {
            filtered++;
            #if defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 )
            QString tittle("TITLE TL2Server v1.0 pkt filter(%1)");
            tittle=tittle.arg(filtered);
                system(tittle.toAscii().data());
            #endif
            return false;
        }
    return true;
}
bool FILTER_UDP(quint16 cmd){
    for(int i=0;i<DEBUG_UDP_FILTER_COUNT;i++)
        if(DEBUG_UDP_FILTER[i]==cmd)
        {
            filtered++;
            #if defined( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 )
            QString tittle("TITLE TL2Server v1.0 pkt filter(%1)");
            tittle=tittle.arg(filtered);
                system(tittle.toAscii().data());
            #endif
            return false;
        }
    return true;
}
void setup_network()
{
    net = new NetTools();
    wanIP = net->GetIp(WAN_METOD);
    lanIPint = QHostAddress(lanIP).toIPv4Address();
    wanIPint = QHostAddress(wanIP).toIPv4Address();
}

quint32 GetCorrectIP(quint32 src,quint32 dst)
{

    quint32 ssrc=src>>8;
    quint32 ddst=dst>>8;

    if(ssrc==ddst)
        return src;
    else
        return wanIPint;
}
quint32 GetCorrectIP(QTcpSocket src,QTcpSocket dst)
{
    return GetCorrectIP(src.peerAddress().toIPv4Address(),dst.peerAddress().toIPv4Address());
}

quint32 GetCorrectIP(quint32 dst)
{
    return GetCorrectIP(lanIPint,dst);
}
